﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Objects;
using System.Data;
using System.Data.Entity;
using System.Reflection;
using System.Collections;
using System.Linq.Expressions;

namespace dominioEFprueba
{
    internal class Repositorio<T,U> : IRepositorio<T,U>
        where T:class
        where U: DbContext
    {
        public U contexto { get; set; }
        public Repositorio()
        {
            //Database.SetInitializer<U>(new DropCreateDatabaseIfModelChanges<U>());
            Database.SetInitializer<U>(new CreateDatabaseIfNotExists<U>());
        }

        public void insertarTodo(T entidad)
        {

            contexto.Set<T>().Add(entidad);
            contexto.SaveChanges(); 
            
        }

        private object marcarEntidad(object entidad, Type[] clasesGuardar)
        {
            PropertyInfo[] propiedades = entidad.GetType().GetProperties().
                Where(pi=>(pi.PropertyType.Namespace == typeof(T).Namespace && 
                    !clasesGuardar.Contains(pi.PropertyType)) ||
                    pi.PropertyType.Name.Contains(typeof(ICollection).Name) ||
                    pi.PropertyType.Name.Contains(typeof(IList).Name)
                    ).ToArray();
            object propiedadEntidad = null;
            foreach (PropertyInfo pi in propiedades)
            {
                propiedadEntidad = pi.GetValue(entidad, null);
                if (pi.PropertyType.Namespace == typeof(T).Namespace)
                {//es de dominio
                    if (!clasesGuardar.Contains(pi.PropertyType))
                    {
                        contexto.Set(pi.PropertyType).Attach(propiedadEntidad);
                        contexto.Entry(propiedadEntidad).State = EntityState.Unchanged;
                    }
                    marcarEntidad(propiedadEntidad, clasesGuardar);
                }
                if (pi.PropertyType.Name.Contains(typeof(ICollection).Name))
                {
                    ICollection coleccion = propiedadEntidad as ICollection;
                    foreach (var item in coleccion)                    
                        marcarEntidad(item, clasesGuardar);                    
                }
                if (pi.PropertyType.Name.Contains(typeof(IList).Name))
                {
                    IList lista = propiedadEntidad as IList;
                    foreach (var item in lista)                    
                        marcarEntidad(item, clasesGuardar);                    
                }
            }            
            return entidad;
        }


        public void insertar(T entidad,Type[] clasesGuardar)
        {            
            entidad = (T)marcarEntidad(entidad, clasesGuardar);
            contexto.Set<T>().Add(entidad);                
        }


        public void actualizar(T entidad)
        {
            contexto.Set<T>().Attach(entidad);
            contexto.Entry<T>(entidad).State = EntityState.Modified;                         
        }
        public void borrar(T entidad)
        {
            contexto.Set<T>().Attach(entidad);
            contexto.Set<T>().Remove(entidad);
        }
        public T obtenerPorId(object id)
        {
            return contexto.Set<T>().Find(id);            
        }
        public IEnumerable<T> listarTodo()
        {
            return contexto.Set<T>();            
        }

        public IEnumerable<T> buscar(Expression<Func<T, bool>> expresion)
        {
            return contexto.Set<T>().Where(expresion);            
        }

        public IEnumerable<T> buscar(Expression<Func<T, bool>> expresion, string path)
        {
            return contexto.Set<T>().Include(path).Where(expresion);            
        }


    }
}
